package com.tbs.async.aop;

import com.tbs.async.annotation.LongTermAsync;
import com.tbs.common.error.AssertUtil;
import com.tbs.common.util.base.StrUtil;
import com.tbs.common.util.framework.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.Executors;

/**
 * 长期异步切面
 *
 * @author abstergo
 */
@Aspect
@Slf4j
public class LongTermAsyncAop {

    @Around("@annotation(com.tbs.async.annotation.LongTermAsync)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature methodSignature = (MethodSignature)point.getSignature();
        AssertUtil.isTrue(methodSignature.getReturnType() != void.class, "长期异步函数无返回值函数");
        LongTermAsync longTermAsync = methodSignature.getMethod().getDeclaredAnnotation(LongTermAsync.class);
        if (longTermAsync == null) {
            return point.proceed();
        }

        String threadName = StrUtil.isNotEmpty(longTermAsync.value()) ? longTermAsync.value()
            : methodSignature.getDeclaringTypeName() + "-" + methodSignature.getName();
        Object[] r = new Object[1];
        log.debug("start one long term thread {} for {}", threadName, methodSignature.toLongString());
        Executors.newSingleThreadExecutor(new CustomizableThreadFactory(threadName)).execute(() -> {
            try {
                r[0] = point.proceed();
            } catch (Throwable throwable) {
                SpringUtil.getBeanSafe(longTermAsync.onThreadError(), (e) -> {
                    log.error("线程执行错误.", e);
                }).onThreadError(throwable, Thread.currentThread());
            }
        });
        return r[0];
    }

}
